package com.ssm.controller;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.math.BigInteger;
import java.security.AuthProvider;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.prefs.BackingStoreException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.core.Request;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit;
import com.alibaba.druid.support.logging.Resources;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.deser.Deserializers.Base;
import com.ssm.exception.ExceptionCode;
import com.ssm.exception.SsmException;
import com.ssm.exception.WebException;
import com.ssm.model.Model;
import com.ssm.model.bean.MenuList;
import com.ssm.model.bean.SsmActionLog;
import com.ssm.model.bean.SsmActions;
import com.ssm.model.bean.SsmResources;
import com.ssm.model.bean.SsmUserRules;
import com.ssm.model.bean.SsmUsers;
import com.ssm.model.bean.SsmWebSetting;
import com.ssm.model.mapper.ActionLogMapper;
import com.ssm.model.mapper.ActionMapper;
import com.ssm.model.mapper.BaseMapper;
import com.ssm.model.mapper.ResourcesMapper;
import com.ssm.model.mapper.UserInfoMapper;
import com.ssm.model.mapper.UserRuleMapper;
import com.ssm.model.mapper.WebSettingMapper;
import com.ssm.util.ImageUtils;
import com.ssm.util.SSMUtil;
import com.ssm.util.WebSettingUtil;

import tk.mybatis.mapper.entity.EntityTable;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;

/**
 * SSM Controller公共类
 * @author WWT<245108903@qq.com>
 * @version 2016/1/29
 * @param <T>
 * @param <T>
 * */
@Controller
public class SSMController<T>  {

	protected final  String CURRENT_LOGIN_USER="loginuser"; 
	/**
	 * Model层操作对象
	 */
	@Autowired(required=true)
	protected Model M;
	/**
	 * 网站设置获取工具
	 */
	@Autowired(required=true)
	protected WebSettingUtil S;
	
	/**
	 * 获取当前登录用户id
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月1日 下午10:49:56
	 *
	 * @return id
	 */
	protected int getUserID(HttpServletRequest request) {
		return getLoginUser(request).getId();
	}
	

	
	
	/**
	 * 获取当前登录用户
	 *  @author <546895488@qq.com>
	 * @return 
	 * @return user
	 */
	protected SsmUsers  getLoginUser(HttpServletRequest request) {
		HttpSession session=request.getSession();
		Object userObject=session.getAttribute(CURRENT_LOGIN_USER);
		if(userObject!=null&&userObject instanceof SsmUsers)
			return (SsmUsers)userObject;
		else 
			throw new SsmException(ExceptionCode.NOT_LOGIN_USER);
	}
	
	
	/**
	 * 获取当前时间戳
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年1月31日 下午12:12:42
	 *
	 * @return 时间戳
	 */
	protected Long nowTime()
	{
		return (new Date()).getTime();
	}
	
	/**
	 * 删除信息
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月1日 下午10:57:16
	 * @param <MT>
	 * @param <ST>
	 *
	 * @param tableName
	 * @param id
	 * @return
	 */
	protected  <MT extends BaseMapper<T>> int deleteRows(Class<MT> mapperType,Integer []ids) {
		return setStatus(mapperType, ids,-1);
	}
	
	/**
	 * 获取mapper的bean泛型类型
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午6:50:30
	 *
	 * @param mapperType 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private <MT extends BaseMapper<T>> Class<T> getClassT(Class<MT> mapperType)
	{
		Class<T> beanClass=(Class<T>) ((ParameterizedType)(mapperType.getGenericInterfaces()[0])).getActualTypeArguments()[0];
		return beanClass;
	}
	
	/**
	 * 停用信息
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月1日 下午10:57:46
	 *
	 * @param tableName
	 * @param id
	 * @return
	 */
	protected <MT extends BaseMapper<T>> int stopRows(Class<MT> mapperType,Integer[] ids) {
		return setStatus(mapperType, ids,0);
	}
	
	/**
	 * 恢复信息
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月1日 下午10:58:02
	 *
	 * @param tableName
	 * @param id
	 * @return
	 */
	protected <MT extends BaseMapper<T>> int resetRows(Class<MT> mapperType,Integer []ids) {
		return setStatus(mapperType, ids,1);
	}
	
	/**
	 * 修改数据状态操作(在控制器中修改状态直接调用函数即可)
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午6:51:36
	 *
	 * @param mapperType
	 * @param request
	 * @return
	 */
	protected <MT extends BaseMapper<T>> int changeStatus(Class<MT> mapperType,HttpServletRequest request) {
		
		String method=request.getParameter("method");
		String[] idsStr=request.getParameterValues("id");
		if(method==null||idsStr==null||idsStr.length==0)
			throw new SsmException(ExceptionCode.PARAM_NOT_FIND);
		Integer[]ids=new Integer[idsStr.length];
		for(int i=0;i<idsStr.length;i++)
			ids[i]=Integer.parseInt(idsStr[i]);
		int affectNum=0;
		switch (method) {
		case "open":affectNum=this.resetRows(mapperType, ids); break;
		case "close":affectNum=this.stopRows(mapperType, ids); break;
		case "del":affectNum=this.deleteRows(mapperType, ids); break;

		default:
			throw new SsmException(ExceptionCode.PARAM_VALUE_IS_ERROR);
		}
		if(affectNum!=idsStr.length)
			throw new SsmException(ExceptionCode.CHANGE_ROW_NUM_ERROR);
		return affectNum;
		
	}
	
	
	
	/**
	 * 设置数据状态(自定义状态值)
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午6:53:27
	 *
	 * @param mapperType
	 * @param ids
	 * @param status
	 * @return
	 */
	protected <MT extends BaseMapper<T>> int setStatus(Class<MT> mapperType,Integer []ids,int status) {
		
		MT base=M.getMapper(mapperType);
		Class<T> beanClass=getClassT(mapperType);
		Example example=new Example(beanClass);
		Criteria criteria=example.createCriteria();
		List<Integer> list=new ArrayList<Integer>();
		for(Integer id:ids)
			list.add(id);	
		criteria.andIn("id",list);
		int affectNum=0;
		try {
			T bean = beanClass.newInstance();
			Method setStatus=beanClass.getMethod("setStatus",Integer.class);
			setStatus.invoke(bean,status);
			affectNum=base.updateByExampleSelective(bean, example);
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			throw new WebException("初始化失败",e);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			throw new WebException("非法访问",e);
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			throw new WebException("无法确定函数",e);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			throw new WebException("出现安全问题",e);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			throw new WebException("非法参数",e);
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			throw new WebException("调用目标错误",e);
		}
		
		return affectNum;
		
	}
	
	/**
	 * 页面跳转(未实现)
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午6:57:20
	 *
	 * @param message
	 * @param waitSecond
	 * @param status
	 * @param jumpUrl
	 * @return
	 */
	protected ModelAndView dispatchJump (String message,int waitSecond,int status,String jumpUrl) 
	{
		return null;
	}
	
	
	
	
	/**
	 * 将List转换成View中的Table
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月11日 下午7:27:21
	 *
	 * @param mapperType 
	 * @param example 查询条件    null默认status>-1
	 * @param request
	 * @param isToTree 是否使用树状格式
	 */
	protected <MT extends BaseMapper<T>> void List2Table(Class<MT> mapperType,Example example,HttpServletRequest request,boolean isToTree) {
		MT base=M.getMapper(mapperType);
		Integer pageNum= Integer.parseInt(request.getParameter("pageNum")==null?"0":request.getParameter("pageNum"));
		int limit=S.getInteger("pageRowNum");//每页条数
		try {
			if(example==null)
			{
				Class<T>beanType=getClassT(mapperType);
				example=new Example(beanType);
				Criteria criteria=example.createCriteria();
				criteria.andCondition("status>-1");
			}
			List<T> list=base.selectByExampleAndRowBounds(example, new RowBounds(pageNum*limit, limit));
		if(isToTree)
		{
			T obj=list.remove(0);
			list=SSMUtil.List2Tree(list,null, null);
			list.add(0,obj);
		}
		request.setAttribute("LIST",list);
		String html=SSMUtil.tablePageToHtml(request.getRequestURI(),limit,base.selectCountByExample(example),pageNum);
		request.setAttribute("PAGE_HTML", html);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			throw new WebException("出现安全问题",e);
		} catch (IllegalArgumentException e) {
		// TODO Auto-generated catch block
			throw new WebException("非法参数",e);
		}
		
	}
	
	/**
	 * 保存文件到服务器系统中
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午6:59:54
	 *
	 * @param request
	 * @return
	 */
	protected List<String> SaveFile2Local(HttpServletRequest request)
	{
		List<String> savepathList=new ArrayList<>();
		String pathname=request.getRealPath("/upload/");
		CommonsMultipartResolver multiPartResolver=new CommonsMultipartResolver(request.getSession().getServletContext());
		if(multiPartResolver.isMultipart(request))//多部分请求即包含上传文件
		{
			MultipartHttpServletRequest multirequest=null;
			if(request instanceof MultipartHttpServletRequest)
				multirequest=(MultipartHttpServletRequest)request;
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
			Iterator<String> filenames=multirequest.getFileNames();
			Random random=new Random();
			ResourcesMapper resourcesMapper=M.getMapper(ResourcesMapper.class);
			while(filenames.hasNext())
			{
				MultipartFile file=multirequest.getFile(filenames.next());
				if(file.isEmpty())
					continue;
				Date current= new Date();
				String hashString;
				try {
					byte[] uploadBytes = file.getBytes();//生成md5
					MessageDigest md5 = MessageDigest.getInstance("MD5");
					byte[] digest = md5.digest(uploadBytes);
					hashString = new BigInteger(1, digest).toString(32);
					SsmResources resources=new SsmResources();
					resources.setMd5(hashString.toUpperCase());
					List<SsmResources> resourcesList=resourcesMapper.select(resources);
					if(resourcesList.size()>0)
					{
						resources=resourcesList.get(0);
						savepathList.add(resources.getSavepath()+"%%"+resources.getShowpath()+"%%"+resources.getMd5());
						continue;
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					throw new WebException("获取上传文件byte失败",e);
				} catch (NoSuchAlgorithmException e) {
					// TODO Auto-generated catch block
					throw new WebException("获取加密编码失败",e);
				}
				File dir=new File(pathname+sdf.format(current));
				if(!dir.exists())
					dir.mkdirs();
				if(dir.isDirectory())
				{
					String filetype;
					switch (file.getContentType()) {
					case "text/plain":filetype="txt";
						break;
					case "image/png":filetype="png";
					break;
					case "application/msword":filetype="doc";
					break;
					default:
						filetype="temp";
						break;
					}
					String saveFilebackStr=(current.getTime()+random.nextInt())+"."+filetype;
					String savepath=dir.getPath()+"/"+saveFilebackStr;
					File saveFile=new File(savepath);
					String thumbFileStr=dir.getPath()+"/thumb_"+saveFilebackStr;
					while(saveFile.exists())
					{	
						saveFilebackStr=(current.getTime()+random.nextInt())+"."+filetype;
						thumbFileStr=dir.getPath()+"/thumb_"+saveFilebackStr;
						savepath=dir.getPath()+"/"+saveFilebackStr;
						saveFile=new File(savepath);
					}
					try {
						if(saveFile.createNewFile())
						{
							file.transferTo(saveFile);
							ImageUtils.scaleByHW(savepath, thumbFileStr,150,150,true);
							savepathList.add("../upload"+"/"+sdf.format(current)+"/"+saveFilebackStr+"%%"+"../upload"+"/"+sdf.format(current)+"/thumb_"+saveFilebackStr+"%%"+hashString.toUpperCase());
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block 
						throw new WebException("上传文件无法创建",e);
					} 
				}
			}
		}
		return savepathList;
	}
	
	/**
	 * 上传单个文件到服务器
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午7:00:54
	 *
	 * @param request
	 * @param resources
	 * @return
	 */
	protected int UploadOneFile(HttpServletRequest request,SsmResources resources) {
		int saveFileNum=0;
		ResourcesMapper resourcesMapper=M.getMapper(ResourcesMapper.class);
		List<String> pathList=SaveFile2Local(request);
		
		for (String path : pathList) {
			saveFileNum++;
			if(resources.getId()==null)//添加文件
			{
				resources.setCreatetime(nowTime().toString());
				resources.setSavepath(path.split("%%")[0]);
				resources.setShowpath(path.split("%%")[1]);
				resources.setMd5(path.split("%%")[2]);
				resources.setUserid(getUserID(request));
				/* md5 sha1 文件重复判断 没有实现  */
				resourcesMapper.insertSelective(resources);
			}
			else {//修改文件
				SsmResources oldResource=resourcesMapper.selectByPrimaryKey(resources.getId());
				if(oldResource!=null&&oldResource.getUserid()==getUserID(request))//校验是否是文件主人 是
				{
					resources.setAlerttime(nowTime().toString());
					resources.setSavepath(path.split("%%")[0]);
					resources.setShowpath(path.split("%%")[1]);
					resources.setMd5(path.split("%%")[2]);
					resourcesMapper.updateByPrimaryKeySelective(resources);
				}
				else {//否
					throw new SsmException(ExceptionCode.IS_NOT_SELF_RESOURCE);
				}
			}
		}
		if(pathList.size()==0&&resources.getId()!=null)
		{
			SsmResources oldResource=resourcesMapper.selectByPrimaryKey(resources.getId());
			if(oldResource!=null&&oldResource.getUserid()==getUserID(request))//校验是否是文件主人 是
			{
				resources.setAlerttime(nowTime().toString());
				resourcesMapper.updateByPrimaryKeySelective(resources);
			}
			else {//否
				throw new SsmException(ExceptionCode.IS_NOT_SELF_RESOURCE);
			}
		}
		
		return saveFileNum;
	}
	

	/**
	 * 执行行为
	 * @author WTC E-mail:546895488@qq.com 
	 * @version 创建时间：2016年2月25日 下午4:19:09 
	 * @param destinct 行为名
	 * @param request
	 */
	protected void analysisAction(String destinct,HttpServletRequest request){
		Log log = LogFactory.getLog(this.getClass());   
		
		ActionMapper am=M.getMapper(ActionMapper.class);
		ActionLogMapper alm=M.getMapper(ActionLogMapper.class);
		//获取动作
		SsmActions sa=new SsmActions();
		sa.setName(destinct);
		try {
			sa=am.selectOne(sa);
		} catch (Exception e) {
			throw new SsmException(ExceptionCode.GET_DATA_ROW_NUM_ERROR);
		}
		
		//获取相应动作规则
		String rule=sa.getRule();
		String rulelog=sa.getLogrule();
		
		if(rule==null||rule.equals(""))
		{
			if(rulelog==null)//没动作规则，没日志规则
			{
				SsmActionLog sal=new SsmActionLog();
				sal.setUserid(this.getUserID(request));
				sal.setActionid(sa.getId());
				sal.setContent("操作URL:"+request.getRequestURI());	
				sal.setStatus(1);
				sal.setCreatetime(Long.toString(this.nowTime()));
				alm.insert(sal);
			}
			else//没动作规则，有日志规则
			{
				SsmActionLog sal=new SsmActionLog();
				sal.setUserid(this.getUserID(request));
				sal.setActionid(sa.getId());
				String dynamicrulelog=rulelog;
				dynamicrulelog=dynamicrulelog.replaceAll("name", this.getLoginUser(request).getUsername());
				dynamicrulelog=dynamicrulelog.replaceAll("time", this.nowTime().toString());
				sal.setContent(dynamicrulelog);	
				sal.setStatus(1);
				sal.setCreatetime(Long.toString(this.nowTime()));			
				if(alm.insert(sal)<=0)
					throw new SsmException(ExceptionCode.DATE_INSTANT_ERROR);
				
					
				
			}
		}
		else//有动作规则
		{
			UserInfoMapper uim=M.getMapper(UserInfoMapper.class);
			/*
			 * 获取规则
			 */
			String table;
			String thisrule;
			double fcycle;
			int max;
			String []rules=rule.split("\\|");
			
			table=rules[0];
			thisrule=rules[1];
			fcycle=Double.valueOf(rules[2]);
			max=Integer.parseInt(rules[3]);
			
			long cycle=(long)(fcycle*3600000.0);
			Example example=new Example(SsmActionLog.class);
			long a=this.nowTime()-cycle;//
			example.createCriteria().andCondition(""+a+"<createtime and userid="+this.getUserID(request)+" and actionid="+sa.getId()+"");
			System.out.println(alm.selectCountByExample(example));
			if(alm.selectCountByExample(example)>max)
			{
				throw new WebException("超出访问次数");
			}
			else
			{
			
				try
				{
					//System.out.println("update "+table+" set "+thisrule+" where userId="+user.getId()+"");
					uim.Ssmupdate(table, thisrule, this.getUserID(request));
					
					if(rulelog==null){//有动作规则，无日志规则
						SsmActionLog sal=new SsmActionLog();
						sal.setUserid(this.getUserID(request));
						sal.setActionid(sa.getId());
						sal.setContent("操作URL:"+request.getRequestURI());	
						sal.setStatus(1);
						sal.setCreatetime(Long.toString(this.nowTime()));
						alm.insert(sal);
					}
					else//有动作规则，有日志规则
					{
						SsmActionLog sal=new SsmActionLog();
						sal.setUserid(this.getUserID(request));
						sal.setActionid(sa.getId());
						String dynamicrulelog=rulelog;
						dynamicrulelog=dynamicrulelog.replaceAll("name", this.getLoginUser(request).getUsername());
						dynamicrulelog=dynamicrulelog.replaceAll("time", this.nowTime().toString());
						sal.setContent(dynamicrulelog);
						sal.setStatus(1);
						sal.setCreatetime(Long.toString(this.nowTime()));
						alm.insert(sal);
	
					}
				}
				catch(Exception e)
				{
					throw new SsmException(ExceptionCode.DATE_INSTANT_ERROR,e);
				}
			}
		}
	}
	
	
	
	
	/**
	 * 添加一个cookie
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午7:25:13
	 *
	 * @param response
	 * @param name
	 * @param value
	 */
	protected  void addCookie(HttpServletResponse response,String name,String value){
	    Cookie cookie = new Cookie(name,value);
	    WebSettingMapper web=M.getMapper(WebSettingMapper.class);
		SsmWebSetting setting=new SsmWebSetting();
		setting.setName("usercode_cycle");
		setting.setStatus(1);
		setting=web.selectOne(setting);
		int cycle=Integer.valueOf(setting.getValue());
	    cookie.setMaxAge(cycle*60);//s为单位
	    response.addCookie(cookie);
	}
	
	
	/**
	 * 根据name获取一个cookie
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午7:25:30
	 *
	 * @param request
	 * @param name
	 * @return
	 */
	protected  Cookie getCookieByName(HttpServletRequest request,String name){
	    Map<String,Cookie> cookieMap = ReadCookieMap(request);
	    if(cookieMap.containsKey(name)){
	        Cookie cookie = (Cookie)cookieMap.get(name);
	        return cookie;
	    }else{
	        return null;
	    }   
	}
	
	
	/**
	 * 获取所有cookie返回Map<String,Cookie>
	 * @author 危文涛<245108903@qq.com>
	 * @version 2016年2月29日 下午7:25:47
	 *
	 * @param request
	 * @return
	 */
	private  Map<String,Cookie> ReadCookieMap(HttpServletRequest request){  
	    Map<String,Cookie> cookieMap = new HashMap<String,Cookie>();
	    Cookie[] cookies = request.getCookies();
	    if(null!=cookies){
	        for(Cookie cookie : cookies){
	            cookieMap.put(cookie.getName(), cookie);
	        }
	    }
	    return cookieMap;
	}
	
	

}
